#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/stat.h>
#include <sys/statfs.h>
#include <dirent.h>
#include <fcntl.h>

#include "storage.h"
#include "gdsl.h"
#include "rsc.h"

zlog_category_t *zc_rsc;

static st_rsc_dev_meta dev_meta;
static st_rsc_content_meta cont_meta;
static gdsl_list_t dev_list = NULL;
static int storage_runflag = 0;
static pthread_t storage_tid;

/*************** gdsl callback functions ************************/
/** gdsl_write_func_t */
static void write_dev_info(const gdsl_element_t E, FILE *OUTPUT_FILE, gdsl_location_t LOCATION, void *USER_DATA)
{
	st_rsc_dev_info *info = (st_rsc_dev_info *)E;
	fprintf(OUTPUT_FILE,"SID:%d\n",info->id);
	fprintf(OUTPUT_FILE,"total_vol = %dM,free = %dM\n",info->total_vol,info->free_vol);
	fprintf(OUTPUT_FILE,"status = %d, rw_flag = %d\n",info->status,info->rw_flag);
	fprintf(OUTPUT_FILE,"dev_node = %s, mpoint = %s\n",info->dev_node,info->mpoint);
}
static void write_content_info(const gdsl_element_t E, FILE *OUTPUT_FILE, gdsl_location_t LOCATION, void *USER_DATA)
{
	st_rsc_content_unit *unit = (st_rsc_content_unit *)E;
	fprintf(OUTPUT_FILE,"Type = %s\n",unit->type==CONT_TYPE_DIR?"dir":"file");
	fprintf(OUTPUT_FILE,"parent name= %s, name = %s\n",unit->pname,unit->name);
	fprintf(OUTPUT_FILE,"size = %d\n",unit->size);
}
//////////////////////////////////////////////////////

static gdsl_element_t rsc_alloc_dev_unit(void *unit)
{
	st_rsc_dev_info *info = NULL;

	info = malloc(sizeof(st_rsc_dev_info));
	if(info == NULL)
		return NULL;
	memcpy(info,unit,sizeof(st_rsc_dev_info));
	return info;
}
static void rsc_free_dev_unit(gdsl_element_t unit)
{
	st_rsc_dev_info *info = (st_rsc_dev_info *)unit;
	pthread_mutex_destroy(&info->lock);
	free(info);
}
static gdsl_element_t rsc_alloc_content_unit(void *unit)
{
	st_rsc_content_unit *cont = NULL;

	cont = malloc(sizeof(st_rsc_content_unit));
	if(cont == NULL)
		return NULL;
	memcpy(cont,unit,sizeof(st_rsc_content_unit));
	return cont;
}
static void rsc_free_content_unit(gdsl_element_t unit)
{
	free(unit);
}

static long int rsc_compare_dir(gdsl_element_t element,void *data)
{
	return strcmp((char*)element,(char*)data);
}
static long int rsc_compare_file(gdsl_element_t element,void *data)
{
	return strcmp((char*)element,(char*)data);
}
static long int rsc_compare_dev(gdsl_element_t element,void *data)
{
	st_rsc_dev_info *info = (st_rsc_dev_info *)element;
	int devid = (int)data;

	return (info->id - devid);
}

//////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
static st_rsc_dev_info *get_dev_item(int dev_id)
{
	if(dev_id < 0 || dev_id > dev_meta.max_num-1)
	{
		zlog_error(zc_rsc,"invalid dev_id = %d\n",dev_id);
		return NULL;
	}
	gdsl_element_t item = gdsl_list_search(dev_list,rsc_compare_dev,(void*)dev_id);
	if(item == NULL)
	{
		zlog_error(zc_rsc,"device [id:%d] doesnot exist!\n",dev_id);
		return NULL;
	}
	return (st_rsc_dev_info*)item;
}
int rsc_dev_mount(int dev_id,char *options)
{
	st_rsc_dev_info *info = get_dev_item(dev_id);
	if(info == NULL)
		return RSC_EFAIL;

	pthread_mutex_lock(&info->lock);
	if(info->status == DEV_STATUS_MOUNT)
	{
		pthread_mutex_unlock(&info->lock);
		return RSC_OK;
	}

	if(info->status != DEV_STATUS_UMOUNT)
	{
		pthread_mutex_unlock(&info->lock);
		zlog_error(zc_rsc,"device [id:%d] has been mounted!\n",dev_id);
		return RSC_EFAIL;
	}

	char dev_file[64]={0};
	snprintf(dev_file,64,"%s/%s","/dev",info->dev_node);
	if(dev_meta.mount(dev_file,info->mpoint,options)<0)
	{
		pthread_mutex_unlock(&info->lock);
		zlog_error(zc_rsc,"mount device [id:%d] failed!\n",dev_id);
		return RSC_EFAIL;
	}
	/* change device status to mounted */
	info->status = DEV_STATUS_MOUNT;
	pthread_mutex_unlock(&info->lock);
	return RSC_OK;
}

int rsc_dev_umount(int dev_id,char *options)
{
	st_rsc_dev_info *info = get_dev_item(dev_id);
	if(info == NULL)
		return RSC_EFAIL;
	
	pthread_mutex_lock(&info->lock);
	if(info->status == DEV_STATUS_UMOUNT)
	{
		pthread_mutex_unlock(&info->lock);
		return RSC_OK;
	}

	if(info->status != DEV_STATUS_MOUNT)
	{
		pthread_mutex_unlock(&info->lock);
		zlog_error(zc_rsc,"device [id:%d] doesnot been mounted!\n",dev_id);
		return RSC_EFAIL;
	}

	if(dev_meta.umount(info->mpoint,options)<0)
	{
		pthread_mutex_unlock(&info->lock);
		zlog_error(zc_rsc,"umount device [id:%d] failed!\n",dev_id);
		return RSC_EFAIL;
	}
	/* change device status to mounted */
	info->status = DEV_STATUS_UMOUNT;
	pthread_mutex_unlock(&info->lock);
	return RSC_OK;
}

int rsc_dev_format(int dev_id,char *options)
{
	if(rsc_dev_umount(dev_id,NULL)!=RSC_OK)
	{
		zlog_error(zc_rsc,"umount device[%d] failed when format it!\n",dev_id);
		return RSC_EFAIL;
	}
	gdsl_element_t item = gdsl_list_search(dev_list,rsc_compare_dev,(void*)dev_id);
	st_rsc_dev_info *info = (st_rsc_dev_info*)item;
	char dev_file[64]={0};

	pthread_mutex_lock(&info->lock);
	snprintf(dev_file,64,"%s/%s","/dev",info->dev_node);
	if(dev_meta.format(dev_file,options)<0)
	{
		pthread_mutex_unlock(&info->lock);
		zlog_error(zc_rsc,"format device [id:%d] failed!\n",dev_id);
		return RSC_EFAIL;
	}
	pthread_mutex_unlock(&info->lock);
	return RSC_OK;
}

int rsc_get_dev_info(int id, st_rsc_dev_info *dev_info)
{
	if(dev_info == NULL)
	{
		zlog_error(zc_rsc,"dev_info is NULL!\n");
		return RSC_EFAIL;
	}

	st_rsc_dev_info *info = (st_rsc_dev_info*)get_dev_item(id);
	if(info == NULL)
		return RSC_EFAIL;
	pthread_mutex_lock(&info->lock);
	memcpy(dev_info,info,sizeof(st_rsc_dev_info));
	pthread_mutex_unlock(&info->lock);
	return RSC_OK;
}

int rsc_get_all_vol(int *total_vol,int *free_vol)
{
	int i = 0;
	st_rsc_dev_info info;
	int vol_t = 0, vol_f = 0;

	if(total_vol == NULL || free_vol == NULL)
	{
		zlog_error(zc_rsc,"invalid params!\n");
		return RSC_EFAIL;
	}
	for(i=0;i<dev_meta.max_num;i++)
	{
		if(rsc_get_dev_info(i,&info)==RSC_OK)
		{
			vol_t += info.total_vol;
			vol_f += info.free_vol;
		}
	}
	*total_vol = vol_t;
	*free_vol = vol_f;

	return RSC_OK;
}

/** return the size has been deleted or freed */
static int rsc_delete_file_byneed(char *dir, int size)
{
	gdsl_list_t flist = NULL;

	flist = rsc_get_file_list(dir,CONT_DATA_ALL);
	if(flist == NULL)
	{
		zlog_info(zc_rsc,"dir [%s] file list NULL!\n",dir);
		return 0;
	}
	gdsl_list_sort(flist,rsc_compare_file);
	
	int free_size = 0;
	char filename[64]={0};
	st_rsc_content_unit *cunit = NULL;
	gdsl_element_t e;
	gdsl_list_cursor_t c = gdsl_list_cursor_alloc(flist);
	for (gdsl_list_cursor_move_to_head (c); (e = gdsl_list_cursor_get_content (c)); gdsl_list_cursor_step_forward (c))
	{
		cunit = (st_rsc_content_unit *)e;
		snprintf(filename,64,"%s/%s",cunit->pname,cunit->name);	
		remove(filename);
		free_size += cunit->size;
		if(free_size >= size)
			break;
	}
	gdsl_list_cursor_free(c);
	gdsl_list_free(flist);

	zlog_info(zc_rsc,"get free space = [%d]B\n",free_size);
	return free_size;
}
static int rsc_free_space_byneed(int size,char *mpoint)
{
	int i = 0;
	st_rsc_dev_info info_cur;
	st_rsc_dev_info info_min;
	st_rsc_content_unit *cunit_min = NULL; /** oldest dir list */
	st_rsc_content_unit *cunit_cur = NULL; /** current dir list */

	gdsl_list_t rlist_min = NULL; /** device oldest root list */
	gdsl_list_t rlist_cur = NULL; /** device current root list */
	for(i=0;i<dev_meta.max_num;i++)
	{
		if(rsc_get_dev_info(i,&info_cur)==RSC_OK
			&& info_cur.status == DEV_STATUS_MOUNT
			&& info_cur.rw_flag == DEV_FLAG_RDWR)
		{
			rlist_cur = rsc_get_root_list(i,CONT_DATA_ALL);
			if(rlist_cur==NULL) continue;// this should not happen
			cunit_cur = (st_rsc_content_unit *)gdsl_list_search_min(rlist_cur,rsc_compare_dir);
			if(rlist_min == NULL) rlist_min = rlist_cur;
			if(cunit_min == NULL) 
			{/** first device */
				cunit_min = cunit_cur;
				memcpy(&info_min,&info_cur,sizeof(info_cur));
			}
			if(cunit_cur!=cunit_min && cunit_cur!=NULL && cunit_min != NULL)
			{
				if(rsc_compare_dir(cunit_cur,cunit_min)<0)
				{/** if current dir is older than last oldest dir,then change it */
					cunit_min = cunit_cur;
					gdsl_list_free(rlist_min);
					rlist_min = rlist_cur;
					memcpy(&info_min,&info_cur,sizeof(info_cur));
				}
				else
				{
					gdsl_list_free(rlist_cur);
				}
			}
		}
	}
	if(rlist_min == NULL)
	{
		zlog_error(zc_rsc,"find oldest dir fail!\n");
		return RSC_EFAIL;
	}
	/** subtract the free volume in the device before deleting oldest files */
	size -= info_min.free_vol<<20; /// keep the same unit: Bytes
	zlog_info(zc_rsc,"need to release [%d]B space!\n",size);

	/** delete files in the dir to free space : size bytes */
	int free_size = 0;
	char dirname[64]={0};
	st_rsc_content_unit *cunit = NULL;
	gdsl_element_t e;

	gdsl_list_sort(rlist_min,rsc_compare_dir);
	gdsl_list_cursor_t c = gdsl_list_cursor_alloc(rlist_min);
	for (gdsl_list_cursor_move_to_head (c); (e = gdsl_list_cursor_get_content (c)); gdsl_list_cursor_step_forward (c))
	{
		cunit = (st_rsc_content_unit *)e;
		snprintf(dirname,64,"%s/%s",cunit->pname,cunit->name);	
		zlog_info(zc_rsc,"scan dir [%s] to get size [%d]B\n",dirname,size);
		free_size += rsc_delete_file_byneed(dirname, size);
		size -= free_size;
		if(size <= 0)
			break;
	}
	gdsl_list_cursor_free(c);
	gdsl_list_free(rlist_min);

	if(size > 0)
	{
		zlog_warn(zc_rsc,"only get [%d]Bytes < [%d]Bytes need!\n",free_size,size);
		return RSC_EFAIL;
	}
	else
	{
		zlog_info(zc_rsc,"get [%d]Bytes free!\n",free_size);
		/* get the mount point */
		strcpy(mpoint,info_min.mpoint);
		return RSC_OK;
	}
}

int rsc_get_avail_dev(int size, char *mpoint)
{
	int i = 0;
	st_rsc_dev_info info;

	if(mpoint == NULL)
	{
		zlog_error(zc_rsc,"invalid params!\n");
		return RSC_EFAIL;
	}
	for(i=0;i<dev_meta.max_num;i++)
	{
		if(rsc_get_dev_info(i,&info)==RSC_OK
			&& info.status == DEV_STATUS_MOUNT
			&& info.rw_flag == DEV_FLAG_RDWR
			&& info.free_vol >= (size>>20))
		{
			strcpy(mpoint,info.mpoint);
			break;
		}
	}
	/** need to delete oldest files to free space */
	if(i>=dev_meta.max_num)
	{
		zlog_info(zc_rsc,"delete oldest files to free space for %dB\n",size);
		return rsc_free_space_byneed(size,mpoint);
	}
	else
		return RSC_OK;
}

/** File APIs */
static void *rsc_get_content_list(const char *dir)
{
	int ret = 0;
	int fnum = 0,i = 0;
	struct dirent **flist = NULL;
	struct stat fstat;
	gdsl_list_t cont_list = NULL;

	if(dir == NULL)
	{
		zlog_error(zc_rsc,"dir is null!\n");
		return NULL;
	}
	memset(&fstat,0,sizeof(fstat));
	fnum = scandir(dir,&flist,NULL,alphasort);
	if(fnum < 0)
	{
		zlog_error(zc_rsc,"scandir error:%s\n",strerror(errno));
		return NULL;
	}
	if(fnum == 2) // it's an empty directory,remove it
	{
		zlog_info(zc_rsc,"dir [%s] is empty,remove it!\n",dir);
		rmdir(dir);
		return NULL;
	}
	cont_list = gdsl_list_alloc("clist",rsc_alloc_content_unit,rsc_free_content_unit);
	if(cont_list == NULL)
	{
		zlog_error(zc_rsc,"gdsl_list_alloc failed!\n");
		return NULL;
	}
	st_rsc_content_unit cunit;
	char cwd_buf[64]={0};
	if(getcwd(cwd_buf,sizeof(cwd_buf))==NULL)
		return NULL;
	if(chdir(dir)<0)
		return NULL;
	for(i=0;i<fnum;i++)
	{
		memset(&cunit,0,sizeof(cunit));
		ret = stat(flist[i]->d_name,&fstat);
		if(ret < 0)
		{
			zlog_error(zc_rsc,"stat %s error:%s!\n",flist[i]->d_name,strerror(errno));
			continue;
		}
		strcpy(cunit.pname,dir);
		strcpy(cunit.name,flist[i]->d_name);
		cunit.size = fstat.st_size;
		cunit.mtime = fstat.st_mtime;
		if(S_ISDIR(fstat.st_mode))
			cunit.type = CONT_TYPE_DIR;
		else
			cunit.type = CONT_TYPE_FILE;
		gdsl_list_insert_tail(cont_list,&cunit);
	}
	/* restore cwd */
	if(chdir(cwd_buf)<0)
		return NULL;

	/** debug */
	zlog_info(zc_rsc,"content list below,num = %ld\n",gdsl_list_get_size(cont_list));
	//gdsl_list_write(cont_list,write_content_info,stdout,NULL);
	return cont_list;
}

void *rsc_get_root_list(int dev_id, int data_type)
{
	st_rsc_dev_info *info = get_dev_item(dev_id);
	if(info == NULL)
		return NULL;

	char root[64]={0};
	pthread_mutex_lock(&info->lock);
	strcpy(root,info->mpoint);
	pthread_mutex_unlock(&info->lock);

	return rsc_get_dir_list(root,data_type);
}

void *rsc_get_dir_list(const char *dir,int data_type)
{
	if(dir == NULL || data_type < 0 || data_type > CONT_DATA_ALL)
	{
		zlog_error(zc_rsc,"invalid params!\n");
		return NULL;
	}
	gdsl_list_t clist = rsc_get_content_list(dir);
	if(clist == NULL || cont_meta.dir_filter[data_type]==NULL)
		return clist;
	gdsl_element_t e;
	gdsl_list_cursor_t c = gdsl_list_cursor_alloc(clist);
	gdsl_list_cursor_move_to_head (c);
	while((e = gdsl_list_cursor_get_content (c)))
	{
		if(!cont_meta.dir_filter[data_type]((st_rsc_content_unit*)e))
			rsc_free_content_unit(gdsl_list_cursor_remove(c));
		else
			gdsl_list_cursor_step_forward(c);
	}
	gdsl_list_cursor_free(c);

	/** debug */
	zlog_info(zc_rsc,"dir list below,num = %ld\n",gdsl_list_get_size(clist));
	//gdsl_list_write(clist,write_content_info,stdout,NULL);

	return clist;
}
void *rsc_get_file_list(const char *dir,int data_type)
{
	if(dir == NULL || data_type < 0 || data_type > CONT_DATA_ALL)
	{
		zlog_error(zc_rsc,"invalid params!\n");
		return NULL;
	}
	gdsl_list_t clist = rsc_get_content_list(dir);
	if(clist == NULL || cont_meta.file_filter[data_type]==NULL)
		return clist;
	gdsl_element_t e;
	gdsl_list_cursor_t c = gdsl_list_cursor_alloc(clist);
	gdsl_list_cursor_move_to_head (c);
	while((e = gdsl_list_cursor_get_content (c)))
	{
		if(!cont_meta.file_filter[data_type]((st_rsc_content_unit*)e))
			rsc_free_content_unit(gdsl_list_cursor_remove(c));
		else
			gdsl_list_cursor_step_forward(c);
	}
	gdsl_list_cursor_free(c);

	/** debug */
	zlog_info(zc_rsc,"filter file list below,num = %ld\n",gdsl_list_get_size(clist));
	//gdsl_list_write(clist,write_content_info,stdout,NULL);
	//gdsl_list_dump(clist,write_content_info,stdout,NULL);

	return clist;
}

int rsc_free_file_list(void *list)
{
	gdsl_list_free((gdsl_list_t)list);
	return 0;
}

int rsc_get_file_info(const char *file, int *file_size)
{
	struct stat fstat;

	memset(&fstat,0,sizeof(fstat));

	if(file == NULL || file_size == NULL)
	{
		zlog_error(zc_rsc,"invalid params!\n");
		return RSC_EPARA;
	}
	if(stat(file,&fstat)<0)
	{
		zlog_error(zc_rsc,"stat %s error!\n",file);
		return RSC_EFAIL;
	}
	*file_size = fstat.st_size;

	return RSC_OK;
}

static int rsc_check_dev_remove(int id)
{
	st_rsc_dev_info *info = get_dev_item(id);
	char dev_file[64]={0};

	if(info == NULL)
		return RSC_EFAIL;

	pthread_mutex_lock(&info->lock);
	snprintf(dev_file,64,"%s/%s","/dev",info->dev_node);
	if(access(dev_file,F_OK)<0)
		info->status = DEV_STATUS_NEXIST;
	else
		info->status = DEV_STATUS_UMOUNT;

	info->total_vol = 0;
	info->free_vol = 0;
	pthread_mutex_unlock(&info->lock);

	return RSC_OK;
}

static int rsc_check_dev_insert(int id)
{
	st_rsc_dev_info *info = get_dev_item(id);
	st_rsc_dev_info new_info;
	memset(&new_info,0,sizeof(new_info));
	new_info.id = -1;
	if(info == NULL)
	{// add dev info 
		info = &new_info;
		info->id = id;
		pthread_mutex_init(&info->lock,NULL);
	}
	struct statfs fstat;
	char spoint[64]={0};
	char msfile[70]={0};
	char test_file[70]={0};
	int fd = 0;

	pthread_mutex_lock(&info->lock);
	memset(&fstat,0,sizeof(fstat));
	snprintf(spoint,64,"%s%d",dev_meta.mpoint,id+1);
	snprintf(msfile,70,"%s/%s",spoint,".msdev");
	snprintf(test_file,70,"%s/%s",spoint,".test");
	if(statfs(spoint,&fstat)<0)
	{
		pthread_mutex_unlock(&info->lock);
		zlog_error(zc_rsc,"statfs %s error!\n",spoint);
		return RSC_EFAIL;
	}
	if(access(msfile,R_OK)<0)
	{
		pthread_mutex_unlock(&info->lock);
		zlog_error(zc_rsc,"check msdev file fail:%s!\n",strerror(errno));
		return RSC_EFAIL;
	}

	info->total_vol = (fstat.f_blocks*fstat.f_bsize)>>20;
	info->free_vol = (fstat.f_bavail*fstat.f_bsize)>>20;
	info->status = DEV_STATUS_MOUNT;
	if((fd=open(test_file,O_WRONLY|O_CREAT,0666))<0)
	{
		zlog_debug(zc_rsc,"open %s file for write fail:%s\n",test_file,strerror(errno));
		info->rw_flag = DEV_FLAG_RDONLY;
	}
	else
	{
		info->rw_flag = DEV_FLAG_RDWR;
		close(fd);
	}
	FILE *fp = NULL;
	int ret = 0;
	fp = fopen(msfile,"r");
	if(fp == NULL)
	{
		pthread_mutex_unlock(&info->lock);
		zlog_error(zc_rsc,"fopen %s error:%s!\n",msfile,strerror(errno));
		return RSC_EFAIL;
	}
	ret = fscanf(fp,"%s",info->dev_node);	
	if(ret != 1)
	{
		pthread_mutex_unlock(&info->lock);
		zlog_error(zc_rsc,"fscanf file failed:%s!\n",strerror(errno));
		return RSC_EFAIL;
	}
	fclose(fp);
	strcpy(info->mpoint,spoint);
	pthread_mutex_unlock(&info->lock);

	if(new_info.id >= 0)
	{
		if(gdsl_list_insert_head(dev_list,info)==NULL)
		{
			zlog_error(zc_rsc,"add dev info error!\n");
			return RSC_OK;
		}
	}

	return RSC_OK;
}

static int rsc_update_dev_info(void)
{
	if(access(dev_meta.mpoint,F_OK)<0)
		return -1;

	int i = 0;
	char spoint[64]={0};
	char msfile[70]={0};
	for(i=0;i<dev_meta.max_num;i++)
	{
		memset(spoint,0,sizeof(spoint));
		snprintf(spoint,sizeof(spoint),"%s%d",dev_meta.mpoint,i+1);
		if(access(spoint,F_OK)<0)
			continue;
		snprintf(msfile,70,"%s/%s",spoint,".msdev");
		if(access(msfile,R_OK)<0)
		{
			zlog_debug(zc_rsc,"check dev[%d] remove..\n",i);
			rsc_check_dev_remove(i);
		}
		else
		{
			zlog_debug(zc_rsc,"check dev[%d] insert..\n",i);
			rsc_check_dev_insert(i);
		}
	}
	return 0;
}

/**
 * @brief finish:status update,loopd-delete .etc 
 */
static void *rsc_storage_process(void *arg)
{
	while(storage_runflag)
	{
		/** debug */
	//	gdsl_list_write(dev_list,write_dev_info,stdout,NULL);
		rsc_update_dev_info();
		sleep(1);
	}
	return NULL;
}

int rsc_init_storage(st_rsc_dev_meta *dmeta,st_rsc_content_meta *cmeta)
{
	if(!storage_runflag)
	{
		storage_runflag = 1;
	}
	else
	{
		zlog_warn(zc_rsc,"rsc_init_storage has been finished!\n");
		return RSC_EFAIL;
	}

	zc_rsc = zlog_get_category(RSC_LOG_CAT);

	if(dmeta == NULL || cmeta == NULL)
	{
		zlog_error(zc_rsc,"invalid params!\n");
		return RSC_EFAIL;
	}

	dev_list = gdsl_list_alloc("dev_list",rsc_alloc_dev_unit,rsc_free_dev_unit);
	if(dev_list == NULL)
	{
		zlog_error(zc_rsc,"gdsl_list_alloc dev_list fail!\n");
		return RSC_EFAIL;
	}
	
	memcpy(&dev_meta,dmeta,sizeof(dev_meta));
	memcpy(&cont_meta,cmeta,sizeof(cont_meta));
	rsc_update_dev_info();

	/** debug */
	gdsl_list_write(dev_list,write_dev_info,stdout,NULL);
	if(pthread_create(&storage_tid,NULL,rsc_storage_process,NULL)<0)
	{
		zlog_error(zc_rsc,"create storage process thread error!\n");
		return RSC_EFAIL;
	}
	return RSC_OK;
}

void rsc_exit_storage(void)
{
	if(storage_runflag)
	{
		storage_runflag = 0;
		pthread_join(storage_tid,NULL);
	}
}

